package cn.ztydata.teachingsystem.heaven.dao.redis;

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisListCommands;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 章节->资源 redis类
 * Created by chenxin on 2014/12/17.
 */
@Repository
public class ChapterRscDao extends BaseRedisDao {
    /**
     * 保存章节与知识点的关系
     * @param nodeId 节点ID
     * @param rscId 资源ID
     * @return Boolean
     *
     * @author cx
     * @since 214-12-17
     */
    public Boolean saveRsc(final long nodeId, final long rscId) {
        SessionCallback<Boolean> sessionCallback = new SessionCallback<Boolean>() {
            @Override
            public Boolean execute(RedisOperations operations) throws DataAccessException {
                operations.multi();
                //获取List操作
                ListOperations<String, Long> listOperations = operations.opsForList();
                //获取Set操作
                SetOperations<String, Long> setOperations = operations.opsForSet();

                //保存章节->资源的关系
                listOperations.leftPush(KeyUtils.chapterRsc(nodeId), rscId);

                //保存资源->章节的关系
                setOperations.add(KeyUtils.rscChapter(rscId), nodeId);

                operations.exec();
                logger.debug("返回为真");
                return true;
            }
        };

        logger.debug("正常返回保存章节与知识点的关系结果");
        return (Boolean)redisTemplate.execute(sessionCallback);
    }

    /**
     * 获取所有资源ID
     *
     * @author chenxin
     * @since 2014/12/17
     */
    public List<Long> getAll(final long nodeId) {
        ListOperations<String, Long> listOperations = redisTemplate.opsForList();

        logger.debug("获取所有资源ID");
        return listOperations.range(KeyUtils.chapterRsc(nodeId), 0, -1);
    }

    /**
     * 删除资源
     *
     * @author chenxin
     * @since 2014/12/17
     */
    public Boolean delete(final long nodeId, final long rscId) {
        SessionCallback<Boolean> sessionCallback = new SessionCallback<Boolean>() {
            @Override
            public Boolean execute(RedisOperations operations) throws DataAccessException {
                operations.multi();

                //删除章节->资源的关系
                operations.opsForList().remove(KeyUtils.chapterRsc(nodeId), 0, rscId);

                //删除资源->章节的关系
                operations.opsForSet().remove(KeyUtils.rscChapter(rscId), nodeId);

                operations.exec();
                logger.debug("返回结果为true");
                return true;
            }
        };

        logger.debug("正常返回删除资源结果");
        return (Boolean)redisTemplate.execute(sessionCallback);
    }

    /**
     * 分页获取资源ID
     *
     * @author chenxin
     * @since 2014/12/17
     */
    public List<Long> getList(final int pageNum, final int pageSize, final long nodeId) {
        ListOperations<String, Long> listOperations = redisTemplate.opsForList();

        logger.debug("分页获取资源ID");
        return listOperations.range(KeyUtils.chapterRsc(nodeId), pageSize * (pageNum - 1), pageNum * pageSize - 1);
    }

    /**
     * 获取资源总数
     *
     * @author chenxin
     * @since 2014/12/17
     */
    public Long getLength(final long nodeId) {
        ListOperations<String, Long> listOperations = redisTemplate.opsForList();

        logger.debug("获取资源总数");
        return listOperations.size(KeyUtils.chapterRsc(nodeId));
    }

    /**
     * 删除章节与资源的关系
     *
     * @author chenxin
     * @since 2014/12/22
     */
    public Boolean deleteAll(final long nodeId) {
        //获取资源ID集合
        final List<Long> rscIds = getAll(nodeId);

        SessionCallback<Boolean> sessionCallback = new SessionCallback<Boolean>() {
            @Override
            public Boolean execute(RedisOperations operations) throws DataAccessException {
                operations.multi();
                //获取List操作
                ListOperations<String, Long> listOperations = operations.opsForList();
                //获取Set操作
                SetOperations<String, Long> setOperations = operations.opsForSet();

                for (Long rscId : rscIds) {
                    //删除章节->资源的关系
                    operations.opsForList().remove(KeyUtils.chapterRsc(nodeId), 0, rscId);

                    //删除资源->章节的关系
                    operations.opsForSet().remove(KeyUtils.rscChapter(rscId), nodeId);
                }

                operations.exec();
                return true;
            }
        };

        return (Boolean)redisTemplate.execute(sessionCallback);
    }

    /**
     * 更新资源顺序
     *
     * @author chenxin
     * @since 2014/12/30
     */
    public Boolean updateRscPosition(final long nodeId, final long draggedId, final long dependedId, final int type) {
        final RedisListCommands.Position position;
        if (type == 1) {
            logger.debug("如果：type == 1");
            position = RedisListCommands.Position.BEFORE;
        }
        else if (type == 2) {
            logger.debug("如果：type == 2");
            position = RedisListCommands.Position.AFTER;
        }
        else {
            logger.debug("默认返回false");
            return false;
        }

        final byte[] key = redisTemplate.getKeySerializer().serialize(KeyUtils.chapterRsc(nodeId));
        final byte[] draggedIdSerialized = redisTemplate.getValueSerializer().serialize(draggedId);
        final byte[] dependedIdSerialized = redisTemplate.getValueSerializer().serialize(dependedId);

        RedisCallback<Boolean> redisCallback = new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                connection.multi();

                //删除被拖拽节点
                connection.lRem(key, 0, draggedIdSerialized);

                //在参照节点之前或之后插入拖拽节点
                connection.lInsert(key, position, dependedIdSerialized, draggedIdSerialized);

                connection.exec();
                return true;
            }
        };

        logger.debug("更新资源顺序结果");
        return (Boolean) redisTemplate.execute(redisCallback);
    }
}
